"""
范围分析核心逻辑

实现需求范围澄清的核心分析功能
"""

import re
from typing import List, Dict, Any, Tuple, Optional
from collections import Counter
import jieba
from modules.specification_fixer.models.requirement_scope import RequirementScope
from modules.specification_fixer.utils.logger import get_logger, ContextLogger, log_performance

logger = get_logger(__name__)


class ScopeAnalyzer:
    """范围分析器"""

    def __init__(self):
        """初始化分析器"""
        # 核心功能关键词
        self.core_keywords = [
            "文档", "分析", "清晰度", "评估", "需求", "提取", "范围", "确认",
            "澄清", "处理", "识别", "验证", "检查"
        ]

        # 非核心功能关键词
        self.non_core_keywords = [
            "资产", "管理", "IP", "知识产权", "账号", "密码", "认证", "授权",
            "用户", "权限", "安全", "登录", "注册"
        ]

        # 功能类别映射
        self.category_mapping = {
            "文档分析": ["文档", "分析", "处理", "解析"],
            "需求管理": ["需求", "提取", "识别", "澄清"],
            "质量评估": ["清晰度", "评估", "检查", "验证"],
            "资产管理": ["资产", "管理", "维护"],
            "用户管理": ["用户", "账号", "密码", "认证"],
            "权限管理": ["权限", "授权", "安全"]
        }

    @log_performance("核心功能识别")
    def identify_core_functions(self, requirements: Dict[str, Any]) -> List[str]:
        """识别核心功能"""
        with ContextLogger(logger, "核心功能识别"):
            if not requirements:
                raise ValueError("需求数据不能为空")

            if not isinstance(requirements, dict):
                raise ValueError("需求数据格式错误，应为字典类型")

            logger.info(f"开始识别核心功能，需求数量: {len(requirements)}")

            core_functions = []
            excluded_functions = []
            errors = []

            for req_id, req_data in requirements.items():
                try:
                    if not isinstance(req_data, dict):
                        errors.append(f"需求 {req_id} 数据格式错误")
                        continue

                    description = req_data.get('description', '')
                    category = req_data.get('category', '')
                    priority = req_data.get('priority', '')

                    # 验证必要字段
                    if not description or not description.strip():
                        errors.append(f"需求 {req_id} 缺少描述信息")
                        continue

                    # 基于关键词和分类判断
                    if self._is_core_function(description, category, priority):
                        core_functions.append(req_id)
                        logger.debug(f"识别为核心功能: {req_id}")
                    else:
                        excluded_functions.append(req_id)
                        logger.debug(f"识别为非核心功能: {req_id}")

                except Exception as e:
                    errors.append(f"处理需求 {req_id} 时出错: {e}")
                    logger.warning(f"处理需求 {req_id} 时出错: {e}")

            # 验证分析结果
            if errors:
                logger.warning(f"分析过程中发现 {len(errors)} 个错误: {errors}")

            if not core_functions and not excluded_functions:
                raise ValueError("无法从提供的需求数据中识别出任何功能")

            logger.info(f"核心功能识别完成 - 核心功能: {len(core_functions)}，排除功能: {len(excluded_functions)}")
            return core_functions

    def identify_excluded_functions(self, requirements: Dict[str, Any]) -> List[str]:
        """识别排除功能"""
        if not requirements:
            raise ValueError("需求数据不能为空")

        if not isinstance(requirements, dict):
            raise ValueError("需求数据格式错误，应为字典类型")

        excluded_functions = []
        errors = []

        for req_id, req_data in requirements.items():
            try:
                if not isinstance(req_data, dict):
                    errors.append(f"需求 {req_id} 数据格式错误")
                    continue

                description = req_data.get('description', '')
                category = req_data.get('category', '')

                # 验证必要字段
                if not description or not description.strip():
                    errors.append(f"需求 {req_id} 缺少描述信息")
                    continue

                if self._is_excluded_function(description, category):
                    excluded_functions.append(req_id)

            except Exception as e:
                errors.append(f"处理需求 {req_id} 时出错: {e}")
                logger.warning(f"处理需求 {req_id} 时出错: {e}")

        if errors:
            logger.warning(f"识别排除功能时发现 {len(errors)} 个错误: {errors}")

        return excluded_functions

    def create_requirement_scope(self, core_functions: List[str],
                               excluded_functions: List[str],
                               justification: str) -> RequirementScope:
        """创建需求范围定义"""
        if not core_functions:
            raise ValueError("核心功能列表不能为空")

        if not justification.strip():
            raise ValueError("范围定义理由不能为空")

        # 生成范围名称
        scope_name = self._generate_scope_name(core_functions)

        # 创建范围定义
        scope = RequirementScope.create_new(
            scope_name=scope_name,
            core_functions=core_functions,
            justification=justification,
            excluded_functions=excluded_functions
        )

        logger.info(f"创建需求范围: {scope_name}, 核心功能: {len(core_functions)}")
        return scope

    def validate_scope_completeness(self, scope: RequirementScope) -> bool:
        """验证范围完整性"""
        validation_result = scope.validate_completeness()
        return validation_result['is_valid']

    def analyze_requirement_relevance(self, requirement_description: str,
                                    core_keywords: List[str] = None,
                                    non_core_keywords: List[str] = None) -> float:
        """分析需求相关性"""
        if not requirement_description:
            return 0.0

        core_keywords = core_keywords or self.core_keywords
        non_core_keywords = non_core_keywords or self.non_core_keywords

        # 分词
        words = list(jieba.cut(requirement_description.lower()))
        word_count = Counter(words)

        # 计算核心相关性得分
        core_score = sum(word_count.get(keyword.lower(), 0) for keyword in core_keywords)
        non_core_score = sum(word_count.get(keyword.lower(), 0) for keyword in non_core_keywords)

        # 归一化得分
        total_words = len(words)
        if total_words == 0:
            return 0.0

        relevance_score = (core_score - non_core_score * 0.5) / total_words
        return max(0.0, min(1.0, relevance_score))

    def extract_scope_boundaries(self, requirements: Dict[str, Any]) -> Dict[str, List[str]]:
        """提取范围边界"""
        includes = set()
        excludes = set()

        for req_data in requirements.values():
            if isinstance(req_data, dict):
                description = req_data.get('description', '')

                # 基于关键词分类
                category = self._categorize_function(description)
                if category == "核心":
                    includes.update(self._get_function_categories(description))
                else:
                    excludes.update(self._get_function_categories(description))

        return {
            "includes": sorted(list(includes)),
            "excludes": sorted(list(excludes))
        }

    def _is_core_function(self, description: str, category: str = '', priority: str = '') -> bool:
        """判断是否为核心功能"""
        description_lower = description.lower()

        # 直接分类判断
        if category.lower() in ['core', '核心', '必须']:
            return True
        if category.lower() in ['non_core', '非核心', '可选', '排除']:
            return False

        # 基于优先级判断
        if priority.lower() in ['high', 'p1', '必须']:
            return True
        if priority.lower() in ['low', 'p3', '可选']:
            return False

        # 基于关键词判断
        core_matches = sum(1 for keyword in self.core_keywords if keyword in description_lower)
        non_core_matches = sum(1 for keyword in self.non_core_keywords if keyword in description_lower)

        return core_matches > non_core_matches

    def _is_excluded_function(self, description: str, category: str = '') -> bool:
        """判断是否为排除功能"""
        description_lower = description.lower()

        # 直接分类判断
        if category.lower() in ['non_core', '非核心', '可选', '排除']:
            return True

        # 基于关键词判断
        return any(keyword in description_lower for keyword in self.non_core_keywords)

    def _generate_scope_name(self, core_functions: List[str]) -> str:
        """生成范围名称"""
        if len(core_functions) == 1:
            return f"需求范围-{core_functions[0]}"
        else:
            return f"需求范围-{len(core_functions)}项核心功能"

    def _categorize_function(self, description: str) -> str:
        """对功能进行分类"""
        description_lower = description.lower()

        # 检查非核心关键词
        if any(keyword in description_lower for keyword in self.non_core_keywords):
            return "非核心"

        # 检查核心关键词
        if any(keyword in description_lower for keyword in self.core_keywords):
            return "核心"

        return "未明确"

    def _get_function_categories(self, description: str) -> List[str]:
        """获取功能所属类别"""
        categories = []
        description_lower = description.lower()

        for category, keywords in self.category_mapping.items():
            if any(keyword in description_lower for keyword in keywords):
                categories.append(category)

        return categories or ["其他"]

    def analyze_scope_complexity(self, scope: RequirementScope) -> Dict[str, Any]:
        """分析范围复杂度"""
        complexity_factors = {
            "function_count": len(scope.core_functions),
            "category_count": len(scope.scope_boundary.get("includes", [])),
            "justification_length": len(scope.justification),
            "exclusion_count": len(scope.excluded_functions)
        }

        # 计算复杂度得分
        complexity_score = (
            complexity_factors["function_count"] * 2 +
            complexity_factors["category_count"] * 1 +
            min(complexity_factors["justification_length"] / 100, 3) +
            complexity_factors["exclusion_count"] * 1
        )

        if complexity_score <= 5:
            complexity_level = "简单"
        elif complexity_score <= 10:
            complexity_level = "中等"
        else:
            complexity_level = "复杂"

        return {
            "factors": complexity_factors,
            "score": complexity_score,
            "level": complexity_level
        }

    def suggest_scope_improvements(self, scope: RequirementScope) -> List[str]:
        """建议范围改进"""
        suggestions = []

        # 检查核心功能数量
        if len(scope.core_functions) < 2:
            suggestions.append("建议增加更多核心功能以确保范围完整性")
        elif len(scope.core_functions) > 10:
            suggestions.append("核心功能过多，建议考虑拆分或精简")

        # 检查排除功能
        if len(scope.excluded_functions) == 0:
            suggestions.append("建议明确标识排除的功能以清晰界定范围")

        # 检查理由充分性
        if len(scope.justification) < 50:
            suggestions.append("建议补充更详细的范围定义理由")

        # 检查类别覆盖
        includes = scope.scope_boundary.get("includes", [])
        if "文档分析" not in includes and "需求管理" not in includes:
            suggestions.append("建议确保包含文档分析或需求管理相关类别")

        return suggestions

    def compare_scopes(self, scope1: RequirementScope, scope2: RequirementScope) -> Dict[str, Any]:
        """比较两个范围定义"""
        core_overlap = set(scope1.core_functions) & set(scope2.core_functions)
        core_only_1 = set(scope1.core_functions) - set(scope2.core_functions)
        core_only_2 = set(scope2.core_functions) - set(scope1.core_functions)

        excluded_overlap = set(scope1.excluded_functions) & set(scope2.excluded_functions)

        similarity_score = len(core_overlap) / max(
            len(set(scope1.core_functions) | set(scope2.core_functions)), 1
        )

        return {
            "similarity_score": similarity_score,
            "core_functions": {
                "overlap": list(core_overlap),
                "only_in_scope1": list(core_only_1),
                "only_in_scope2": list(core_only_2)
            },
            "excluded_functions_overlap": list(excluded_overlap),
            "comparison_summary": {
                "scope1_core_count": len(scope1.core_functions),
                "scope2_core_count": len(scope2.core_functions),
                "overlap_count": len(core_overlap)
            }
        }